package net.lab0.wallstreet;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import net.lab0.tools.StaticRandom;

import com.google.common.collect.Lists;

/**
 * Class to generate example data to test the program
 * 
 * @author 116@lab0.net
 * 
 */
public class ExampleGenerator
{
    private int                       paymentsCount;
    private int                       paymentMaxValue;
    private int                       paymentMinValue;
    
    public static final DecimalFormat format = new DecimalFormat("#.00");
    
    public static class GeneratedData
    {
        public List<Integer> paymentsList;
        public int           transfer;
        public boolean       possible;
        
        public GeneratedData(List<Integer> paymentsList, int transfer, boolean possible)
        {
            super();
            this.paymentsList = paymentsList;
            this.transfer = transfer;
            this.possible = possible;
        }
        
    }
    
    /**
     * Creates a generator of test cases
     * 
     * @param paymentsCount
     *            The number of payments
     * @param paymentMinValue
     *            The minimum value a payment can have
     * @param paymentMaxValue
     *            The maximum value a payment can have (exclusive)
     */
    public ExampleGenerator(int paymentsCount, int paymentMinValue, int paymentMaxValue)
    {
        super();
        this.paymentsCount = paymentsCount;
        this.paymentMaxValue = paymentMaxValue;
        this.paymentMinValue = paymentMinValue;
    }
    
    public GeneratedData generateData()
    {
        int[] payments = StaticRandom.randomArray(paymentsCount, paymentMinValue, paymentMaxValue);
        List<Integer> paymentsList = Lists.newArrayList();
        for (int i : payments)
        {
            paymentsList.add(i);
        }
        Collections.shuffle(paymentsList, StaticRandom.random);
        
        // around 10% of impossible cases
        int transfer = 0;
        boolean possible = true;
        boolean allNull = true;
        if (StaticRandom.random.nextFloat() < 0.1f)
        {
            transfer = StaticRandom.random.nextInt(paymentMaxValue);
            possible = false;// may not be impossible, but no time test it better than that
        }
        else
        {
            int[] valuesToAdd = StaticRandom.randomArray(paymentsCount, 0, 5);// keep 1/5 of the values
            for (int i = 0; i < valuesToAdd.length; ++i)
            {
                // 10.000$ limit set by the exercise -> 1 000 000 as integer
                if (valuesToAdd[i] == 0 && transfer + paymentsList.get(i) < 1000 * 1000)
                {
                    allNull = false;
                    transfer += paymentsList.get(i);
                }
            }
        }
        
        return new GeneratedData(paymentsList, transfer, possible && !allNull);
    }
    
    public static GeneratedData generateDecreasing()
    {
        List<Integer> paymentsList = Lists.newArrayList();
        for (int i = 0; i < 999998; i += 2)
        {
            paymentsList.add(i);
        }
        return new GeneratedData(paymentsList, 1000 * 1000 - 1, false);
    }
    
    public static GeneratedData generatePrimes()
    {
        List<Integer> paymentsList = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37);
        return new GeneratedData(paymentsList, 41, true);
    }
    
    /**
     * Generates a test file
     * 
     * @param outputFile
     *            the output path of the test file
     * @return the bank transfer or -1 if it is not possible
     * @throws FileNotFoundException
     */
    public int generate(String outputFile)
    throws FileNotFoundException
    {
        GeneratedData data = generateData();
        int transfer = data.transfer;
        List<Integer> paymentsList = data.paymentsList;
        
        // write the list to the file
        File input = new File(outputFile);
        if (!input.getParentFile().exists())
        {
            input.getParentFile().mkdirs();
        }
        PrintWriter printWriter = null;
        
        try
        {
            printWriter = new PrintWriter(outputFile);
            printWriter.println(format.format(transfer / 100.0));
            for (int p : paymentsList)
            {
                printWriter.println(format.format(p / 100.0));
            }
        }
        finally
        {
            if (printWriter != null)
            {
                printWriter.close();
            }
        }
        
        return data.possible ? -1 : transfer;
    }
    
    public static void main(String[] args)
    throws FileNotFoundException
    {
        for (int i = 1; i < 10; ++i)
        {
            ExampleGenerator generator = new ExampleGenerator(i * 10, i * 50, i * 200);
            generator.generate("./inputs/example" + i + ".txt");
        }
    }
}
